package com.winexpress.order;

import com.paypal.exception.ClientActionRequiredException;
import com.paypal.exception.HttpErrorException;
import com.paypal.exception.InvalidCredentialException;
import com.paypal.exception.InvalidResponseDataException;
import com.paypal.exception.MissingCredentialException;
import com.paypal.exception.SSLConfigurationException;
import com.paypal.sdk.exceptions.OAuthException;
import com.winexpress.util.Log;
import com.winexpress.util.SessionAttributes;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.GregorianCalendar;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import javax.servlet.ServletContext;
import javax.servlet.annotation.WebServlet;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.ws.WebServiceRef;
import org.xml.sax.SAXException;
import urn.ebay.api.PayPalAPI.DoDirectPaymentReq;
import urn.ebay.api.PayPalAPI.DoDirectPaymentRequestType;
import urn.ebay.api.PayPalAPI.DoDirectPaymentResponseType;
import urn.ebay.api.PayPalAPI.PayPalAPIInterfaceServiceService;
import urn.ebay.apis.CoreComponentTypes.BasicAmountType;
import urn.ebay.apis.eBLBaseComponents.AddressType;
import urn.ebay.apis.eBLBaseComponents.CreditCardDetailsType;
import urn.ebay.apis.eBLBaseComponents.CreditCardTypeType;
import urn.ebay.apis.eBLBaseComponents.CurrencyCodeType;
import urn.ebay.apis.eBLBaseComponents.DoDirectPaymentRequestDetailsType;
import urn.ebay.apis.eBLBaseComponents.ErrorType;
import urn.ebay.apis.eBLBaseComponents.PayerInfoType;
import urn.ebay.apis.eBLBaseComponents.PaymentActionCodeType;
import urn.ebay.apis.eBLBaseComponents.PaymentDetailsType;
import urn.ebay.apis.eBLBaseComponents.PersonNameType;

@SuppressWarnings("serial")
@WebServlet(name = "PaymentManagemet", urlPatterns = {"/paymentManagement/*"})
public class PaymentManagemet extends HttpServlet {

    @WebServiceRef(wsdlLocation = "WEB-INF/wsdl/localhost_8080/WineXpress-war/OrderManagementWS.wsdl")
    private OrderManagementWS_Service service;

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, DatatypeConfigurationException, ParseException {
        response.setContentType("text/html;charset=UTF-8");

        try {
            RequestDispatcher dispatcher;
            ServletContext servletContext = getServletContext();
            HttpSession session = request.getSession(true);
            String page = request.getPathInfo().substring(1);

            OrderManagementWS port = service.getOrderManagementWSPort();
            OrderHistory oh = (OrderHistory) session.getAttribute("orderHistroy");
            OrderHistory trans = null;
            
            session.setAttribute("url", request.getRequestURI());
            session.setAttribute(
                    "relatedUrl",
                    "<ul><li><a href='DCC/DoDirectPayment'>DoDirectPayment</a></li><li><a href='RT/DoReferenceTransaction'>DoReferenceTransaction</a></li><li><a href='RP/CreateRecurringPaymentsProfile'>CreateRecurringPaymentsProfile</a></li></ul>");

            DoDirectPaymentReq doPaymentReq = new DoDirectPaymentReq();

            DoDirectPaymentRequestType pprequest = new DoDirectPaymentRequestType();
            DoDirectPaymentRequestDetailsType details = new DoDirectPaymentRequestDetailsType();
            PaymentDetailsType paymentDetails = new PaymentDetailsType();

            BasicAmountType amount = new BasicAmountType();
            amount.setValue(session.getAttribute("paymentAmount").toString());
            amount.setCurrencyID(CurrencyCodeType.fromValue("USD"));
            paymentDetails.setOrderTotal(amount);

            AddressType shipTo = new AddressType();
            shipTo.setName(request.getParameter("firstName") + " " + request.getParameter("lastName"));
            shipTo.setStreet1(request.getParameter("shippingAddress"));

            shipTo.setPostalCode(request.getParameter("ZIP"));
            paymentDetails.setShipToAddress(shipTo);

            details.setPaymentDetails(paymentDetails);

            CreditCardDetailsType cardDetails = new CreditCardDetailsType();

            cardDetails.setCreditCardType(CreditCardTypeType.fromValue(request.getParameter("creditCardType")));
            cardDetails.setCreditCardNumber(request.getParameter("creditCardNumber"));
            cardDetails.setExpMonth(Integer.parseInt(request.getParameter("expDateMonth")));
            cardDetails.setExpYear(Integer.parseInt(request.getParameter("expDateYear")));
            cardDetails.setCVV2(request.getParameter("cvv2Number"));

            PayerInfoType payer = new PayerInfoType();
            PersonNameType name = new PersonNameType();
            name.setFirstName(request.getParameter("firstName"));
            name.setLastName(request.getParameter("lastName"));

            payer.setPayerName(name);
            payer.setAddress(shipTo);

            cardDetails.setCardOwner(payer);

            details.setCreditCard(cardDetails);

            details.setIPAddress("127.0.0.1");

            details.setPaymentAction(PaymentActionCodeType.fromValue("Authorization"));

            pprequest.setDoDirectPaymentRequestDetails(details);
            doPaymentReq.setDoDirectPaymentRequest(pprequest);

            try {
                Map<String, String> configurationMap = Configuration.getAcctAndConfig();

                // Creating service wrapper object to make an API call by loading configuration map.
                PayPalAPIInterfaceServiceService service1 = new PayPalAPIInterfaceServiceService(configurationMap);

                DoDirectPaymentResponseType ddresponse = service1.doDirectPayment(doPaymentReq);
                response.setContentType("text/html");

                if (ddresponse != null) {
                    session.setAttribute("lastReq", service1.getLastRequest());
                    session.setAttribute("lastResp", service1.getLastResponse());

                    if (ddresponse.getAck().toString().equalsIgnoreCase("SUCCESS")) {
                        request.setAttribute("TransactionID", ddresponse.getTransactionID());
                        request.setAttribute("Amount", ddresponse.getAmount().getValue());
                        System.out.println("Payment " + ddresponse.getAck());

                        //complete the order
                        String address = request.getParameter("shippingAddress");
                        address = address.concat(" " + request.getParameter("postalCode") + " " + request.getParameter("receiver") + "  Tel:" + request.getParameter("phoneNumber"));
                        oh.setShippingAddress(address);
                        oh.setCreditCardNumber(request.getParameter("creditCardNumber"));
                        oh.setIsClosed(true);
                        GregorianCalendar gcal = new GregorianCalendar();
                        XMLGregorianCalendar xgcal = DatatypeFactory.newInstance().newXMLGregorianCalendar(gcal);
                        oh.setDate(xgcal);
                        trans = port.completeOrder(oh);

                        if (trans != null) {
                            session.removeAttribute("items");
                            request.setAttribute("ohID", true);
                            Log.info("customerID = " + SessionAttributes.USER_ID + "payment success. TransactionID " + trans.getId());
                        } else {
                            request.setAttribute("ohID", false);
                            Log.error("customerID = " + SessionAttributes.USER_ID + "payment fail. Item out of stock.");
//                            response.sendRedirect("/WineXpressClient/searchManagement/shop");
                        }
                    } else {
                        Map<Object, Object> map = new LinkedHashMap<>();
                        map.put("Ack", ddresponse.getAck());
                        map.put("Errors", ddresponse.getErrors());
                        request.setAttribute("map", map);
                        String ppResponse = new String();
                        for (ErrorType e : ddresponse.getErrors()) {
                            ppResponse += e.getErrorCode() + ": " + e.getLongMessage() + "; ";
                        }
                        System.out.println("Payment " + ddresponse.getAck());
                        Log.error("customerID = " + SessionAttributes.USER_ID + "payment fail.");
                    }

                    request.setAttribute("history", trans);
                    session.removeAttribute("url");
                    session.removeAttribute("relatedUrl");
                    session.removeAttribute("orderHistory");
                    session.removeAttribute("paymentAmount");

                    //Get Number of Items in Cart
                    int count = 0;
                    if (session.getAttribute("items") == null) {
                        int i = 0;
                        request.setAttribute("itemsnum", i);
                    } else {
                        String items = (String) session.getAttribute("items");
                        String[] array = items.split("\\;");
                        for (int i = 1; i < array.length; i = i + 2) {
                            count = count + Integer.parseInt(array[i]);
                        }
                        request.setAttribute("itemsnum", count);
                    }
                    //End Number of Items in Cart

                }
            } catch (FileNotFoundException | SAXException | ParserConfigurationException | SSLConfigurationException | InvalidCredentialException | UnsupportedEncodingException | HttpErrorException e) {
            } catch (InvalidResponseDataException | ClientActionRequiredException | MissingCredentialException | OAuthException | InterruptedException | IOException e) {
            }

            dispatcher = servletContext.getNamedDispatcher(page);
            if (dispatcher == null) {
                dispatcher = servletContext.getNamedDispatcher("Error");
            }

            dispatcher.forward(request, response);
        } catch (NumberFormatException | ServletException | IOException ex) {
            log("Exception in Payment Management servlet");
            log(ex.getMessage());
        }
    }

    //<editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            processRequest(request, response);
        } catch (DatatypeConfigurationException | ParseException ex) {
            Logger.getLogger(PaymentManagemet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Handles the HTTP <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            processRequest(request, response);
        } catch (DatatypeConfigurationException | ParseException ex) {
            Logger.getLogger(PaymentManagemet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

}
